/*  This file is part of the comicconquer project
    Copyright (C) 2010 Reach <reach334@gmail.com>

    ComicConquer is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This software is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public 
    License along with this software.  If not, see <http://www.gnu.org/licenses/>.

*/

#include "SettingDlg.h"

extern QDialog* g_mainDialog;

enum TabPageSerial
{
    TAB_MODE,
    TAB_VIEW,
    TAB_KEY,
    TAB_GESTURE,
    TAB_ABOUT,

    TAB_END
};

SettingDlg::SettingDlg(CoconProfile* profile, QWidget* parent)
: ui::OnyxDialog(parent),
m_profile(profile),
m_tabbar(this),
m_bOK(tr("确定"), this),
m_bCancel(tr("取消"), this)
{
    In_Log(__FUNCTION__, COCLASSNAME);

    setFixedSize(600, 600);
    setWindowFlags(Qt::FramelessWindowHint);

    updateTitle(tr("设置"));

    CO_MOUSEATTATCH;

    // set layout
    content_widget_.setLayout(&m_vlayout);
    m_vlayout.addWidget(&m_tabbar);
    m_vlayout.addLayout(&m_layoutTab);
    m_vlayout.addLayout(&m_hlayoutDown);
    m_hlayoutDown.addStretch(1);
    m_hlayoutDown.addWidget(&m_bOK);
    m_hlayoutDown.addWidget(&m_bCancel);

    // tab pages
    buildModePage();

    buildViewPage();

    m_keyPage = new KeyPage(m_profile->keyMap, this);
    addPage(m_keyPage, tr("按键分配"), TAB_KEY);

    m_gesturePage = new GesturePage(m_profile->gestureMap, this);
    addPage(m_gesturePage, tr("手势分配"), TAB_GESTURE);

    QString aboutText = tr("CoCon "COCON_VERSION
                           "\n"
                           "\n"
                           "欢迎使用本漫画阅读器！\n"
                           "CoCon为Comic Conquer的简称，致力于在boox\n"
                           "上征服漫画！\n"
                           "\n"
                           "请将BUG和建议提交至作者信箱。\n"
                           "本软件为免费软件，使用本软件所造成的一切\n"
                           "后果由用户自行承担。\n"
                           "\n"
                           "祝你使用愉快！\n"
                           "\n"
                           "            作者：reach\n"
                           "            信箱：reach334@gmail.com\n"
                           "                  2010年5月23日");

    m_aboutPage = new CoTabPage(this);
    addPage(m_aboutPage, tr("关于"), TAB_ABOUT);
    ui::OnyxLabel* aboutLabel = new ui::OnyxLabel(aboutText, m_aboutPage);
    aboutLabel->setIndent(10);
    m_aboutPage->addWidget("about", aboutLabel);

    // connect signals
    connect(&m_bOK, SIGNAL(clicked()), this, SLOT(clickedOK()));
    connect(&m_bCancel, SIGNAL(clicked()), this, SLOT(reject()));
    connect(&m_tabbar, SIGNAL(ButtonClicked(const int)), this, SLOT(tabbarClicked(const int)));

    m_tabbar.ClickButton(0); // select the first tab by default

    Out_Log(__FUNCTION__, COCLASSNAME);
}

bool SettingDlg::event(QEvent* e)
{
    bool ret = ui::OnyxDialog::event(e);

    switch (e->type())
    {
    case QEvent::UpdateRequest:
        {
            refreshScreen();
            return true;
        }
        break;

    case QEvent::KeyPress:
        {
            int i = 0;
        }
        break;

    default:
        break;
    }

    return ret;
}

void SettingDlg::keyPressEvent(QKeyEvent* event)
{
    switch (event->key())
    {
    case Qt::Key_Up:
        {
            QKeyEvent eventSend(event->type(), Qt::Key_Backtab, event->modifiers());
            QApplication::sendEvent(this, &eventSend);
            m_vcScrArea[m_tabbar.GetSelectedButton()]->ensureWidgetVisible(QApplication::focusWidget());
        }
        break;
    case Qt::Key_Left:
        {
            if (QApplication::focusWidget()->parent()->metaObject()->className() == QString("CoRadioButtonGroup"))
            {
                if (static_cast<CoRadioButtonGroup*>(QApplication::focusWidget()->parent())->focusePrev())
                {
                    QKeyEvent eventSend(event->type(), Qt::Key_Backtab, event->modifiers());
                    QApplication::sendEvent(this, &eventSend);
                    m_vcScrArea[m_tabbar.GetSelectedButton()]->ensureWidgetVisible(QApplication::focusWidget());
                }
            }
            else
            {
                QKeyEvent eventSend(event->type(), Qt::Key_Backtab, event->modifiers());
                QApplication::sendEvent(this, &eventSend);
                m_vcScrArea[m_tabbar.GetSelectedButton()]->ensureWidgetVisible(QApplication::focusWidget());
            }
        }
        break;
    case Qt::Key_Down:
        {
            QKeyEvent eventSend(event->type(), Qt::Key_Tab, event->modifiers());
            QApplication::sendEvent(this, &eventSend);
            m_vcScrArea[m_tabbar.GetSelectedButton()]->ensureWidgetVisible(QApplication::focusWidget());
        }
        break;
    case Qt::Key_Right:
        {
            if (QApplication::focusWidget()->parent()->metaObject()->className() == QString("CoRadioButtonGroup"))
            {
                if (static_cast<CoRadioButtonGroup*>(QApplication::focusWidget()->parent())->focuseNext())
                {
                    QKeyEvent eventSend(event->type(), Qt::Key_Tab, event->modifiers());
                    QApplication::sendEvent(this, &eventSend);
                    m_vcScrArea[m_tabbar.GetSelectedButton()]->ensureWidgetVisible(QApplication::focusWidget());
                }
            }
            else
            {
                QKeyEvent eventSend(event->type(), Qt::Key_Tab, event->modifiers());
                QApplication::sendEvent(this, &eventSend);
                m_vcScrArea[m_tabbar.GetSelectedButton()]->ensureWidgetVisible(QApplication::focusWidget());
            }
        }
        break;
    case Qt::Key_PageUp:
        {
            int tabId = (m_tabbar.GetSelectedButton() - 1 + TAB_END) % TAB_END;
            m_tabbar.ClickButton(tabId);
        }
        break;
    case Qt::Key_PageDown:
        {
            int tabId = (m_tabbar.GetSelectedButton() + 1) % TAB_END;
            m_tabbar.ClickButton(tabId);
        }
        break;

    default:
        break;
    }
}

void SettingDlg::refreshScreen(ScreenProxy::Waveform w, bool whole)
{
    ScreenProxy::instance().flush(this, w, whole);
}

void SettingDlg::addPage(CoTabPage* tabPage, const QString& title, int id)
{
    In_Log(__FUNCTION__, COCLASSNAME);

    m_tabbar.AddButton(id, title, QIcon());
    QScrollArea* scrArea = new QScrollArea(this);
    scrArea->setWidget(tabPage);
    scrArea->setWidgetResizable(true);
    m_vcScrArea.append(scrArea);
    m_vcPage.append(tabPage);

    Out_Log(__FUNCTION__, COCLASSNAME);
}

void SettingDlg::tabbarClicked(const int id)
{
    In_Log(__FUNCTION__, COCLASSNAME);

    for (int i = 0; i < m_vcScrArea.count(); i++)
    {
        m_layoutTab.removeWidget(m_vcScrArea[i]);
        m_vcScrArea[i]->setVisible(false);
    }
    m_layoutTab.addWidget(m_vcScrArea[id]);
    m_vcScrArea[id]->setVisible(true);

    if (id == TAB_KEY && !m_isKeyPageInited)
    {
        m_isKeyPageInited = true;
        m_keyPage->initByKeyMap();
    }

    if (id == TAB_GESTURE && !m_isGesturePageInited)
    {
        m_isGesturePageInited = true;
        m_gesturePage->initByGestureMap();
    }

    m_vcPage[id]->setFocus();

    Out_Log(__FUNCTION__, COCLASSNAME);
}

void SettingDlg::buildModePage()
{
    In_Log(__FUNCTION__, COCLASSNAME);

    m_modePage = new CoTabPage(this);
    addPage(m_modePage, tr("模式"), TAB_MODE);
    m_vcScrArea[TAB_MODE]->setWidgetResizable(false);
    m_modePage->resize(500, 470);

    CoGroupBox* gbNavigate = m_modePage->addGroupBox("navigate", tr("导航"));
    CoCheckButton* cbScrollMode = gbNavigate->addCheckButton("scroll mode", tr("卷轴模式"));
    CoCheckButton* cbScrollMark = gbNavigate->addCheckButton("scroll mark", tr("翻页标记"));
    cbScrollMode->restrictOther(cbScrollMark);
    gbNavigate->addStretch(1);
    gbNavigate->addNewLine();
    gbNavigate->addNumberEditor("move distance", tr("滚动距离:"), tr("像素"), 500);
    gbNavigate->addStretch(1);

    CoGroupBox* gbScale = m_modePage->addGroupBox("scale", tr("页面缩放"));
    cbScrollMode->restrictOther(gbScale, true);
    gbScale->addRadioButtonGroup("scale", QStringList()<<tr("适应页面")<<tr("适应宽度")<<tr("适应高度"));
    gbScale->addStretch(1);

    CoGroupBox* gbRotate = m_modePage->addGroupBox("rotate", tr("屏幕方向"));
    gbRotate->addRadioButtonGroup("rotate", QStringList()<<tr("横屏(左手)")<<tr("横屏(右手)")<<tr("竖屏"));
    gbRotate->addStretch(1);

    CoGroupBox* gbFlush = m_modePage->addGroupBox("flush", tr("刷新方式"));
    CoCheckButton* cbFlush = gbFlush->addCheckButton("flush check", tr("局部刷新"));
    CoNumberEditor* edInterval = gbFlush->addNumberEditor("clear interval", tr("        全局刷新间隔:"), tr("次"), 100); 
    cbFlush->restrictOther(edInterval);
    gbFlush->addStretch(1);

    m_modePage->addStretch(1);

    Out_Log(__FUNCTION__, COCLASSNAME);
}

void SettingDlg::initModePage()
{
    In_Log(__FUNCTION__, COCLASSNAME);

    int option = m_profile->imgProfile.option;

    m_modePage->getCheckButton("navigate", "scroll mode")->setChecked(option & Opt_ScrollMode);
    m_modePage->getCheckButton("navigate", "scroll mark")->setChecked(m_profile->iScrollMark);
    m_modePage->getNumberEditor("navigate", "move distance")->setValue(m_profile->iMoveDistance);

    if ((option & Opt_FitToWidth) && (option & Opt_FitToHeight))
    {
        m_modePage->getRadioButtonGroup("scale", "scale")->select(0);
    }
    else if (option & Opt_FitToWidth)
    {
        m_modePage->getRadioButtonGroup("scale", "scale")->select(1);
    }
    else if (option & Opt_FitToHeight)
    {
        m_modePage->getRadioButtonGroup("scale", "scale")->select(2);
    }

    if (option & Opt_SideWards)
    {
        if (m_profile->iSideWardsDirect == 0)
        {
            m_modePage->getRadioButtonGroup("rotate", "rotate")->select(0);
        }
        else
        {
            m_modePage->getRadioButtonGroup("rotate", "rotate")->select(1);
        }
    }
    else
    {
        m_modePage->getRadioButtonGroup("rotate", "rotate")->select(2);
    }

    m_modePage->getCheckButton("flush", "flush check")->setChecked(m_profile->iFlushMode);
    m_modePage->getNumberEditor("flush", "clear interval")->setValue(m_profile->iClearInterval);

    Out_Log(__FUNCTION__, COCLASSNAME);

}

void SettingDlg::saveModePage()
{
    In_Log(__FUNCTION__, COCLASSNAME);

    int& option = m_profile->imgProfile.option;

    option &= ~(Opt_AutoNavigate | Opt_FitToHeight | Opt_FitToWidth | Opt_SideWards | Opt_ScrollMode);
    m_profile->iFlushMode = 0;
    m_profile->iScrollMark = 0;

    if (m_modePage->getCheckButton("navigate", "scroll mode")->isChecked())
    {
        option |= Opt_ScrollMode;
    }

    if (m_modePage->getCheckButton("navigate", "scroll mark")->isChecked())
    {
        m_profile->iScrollMark = 1;
    }

    m_profile->iMoveDistance = m_modePage->getNumberEditor("navigate", "move distance")->getValue();

    switch (m_modePage->getRadioButtonGroup("scale", "scale")->selected())
    {
    case 0:
        option |= (Opt_FitToWidth | Opt_FitToHeight); 
        break;
    case 1:
        option |= Opt_FitToWidth; 
        break;
    case 2:
        option |= Opt_FitToHeight; 
        break;

    default:
        break;
    }

    switch (m_modePage->getRadioButtonGroup("rotate", "rotate")->selected())
    {
    case 0:
        option |= Opt_SideWards; 
        m_profile->iSideWardsDirect = 0;
        break;
    case 1:
        option |= Opt_SideWards; 
        m_profile->iSideWardsDirect = 1;
        break;

    default:
        break;
    }

    if (m_modePage->getCheckButton("flush", "flush check")->isChecked())
    {
        m_profile->iFlushMode = 1;
        m_profile->iClearInterval = m_modePage->getNumberEditor("flush", "clear interval")->getValue();
    }

    Out_Log(__FUNCTION__, COCLASSNAME);
}

void SettingDlg::buildViewPage()
{
    In_Log(__FUNCTION__, COCLASSNAME);

    m_viewPage = new CoTabPage(this);
    addPage(m_viewPage, tr("显示效果"), TAB_VIEW);
    m_vcScrArea[TAB_VIEW]->setWidgetResizable(false);
    m_viewPage->resize(500, 470);

    // divide page
    CoGroupBox* gbDivide = m_viewPage->addGroupBox("divide", tr("页面分割"));
    CoCheckButton* cbDivide = gbDivide->addCheckButton("divide", tr("分割"));
    gbDivide->addStretch(1);
    gbDivide->addNewLine();

    CoGroupBox* gbSequence = m_viewPage->addGroupBox("sequence", tr("阅读顺序"));
    cbDivide->restrictOther(gbSequence);
    gbSequence->addRadioButtonGroup("sequence", QStringList()<<tr("从右到左")<<tr("从左到右"));
    gbSequence->addStretch(1);

    // set grayscale
    CoGroupBox* gbGrayscale = m_viewPage->addGroupBox("grayscale", tr("灰度设置"));
    ui::OnyxPushButton* bGrayscale = gbGrayscale->addPushButton("grayscale", tr("灰度设置"));
    gbGrayscale->addStretch(1);
    connect(bGrayscale, SIGNAL(clicked()), this, SLOT(accept()));
    connect(bGrayscale, SIGNAL(clicked()), g_mainDialog, SLOT(setGrayscale()));

    // cut margin
    CoGroupBox* gbCutMargin = m_viewPage->addGroupBox("cut margin", tr("切白边"));
    CoCheckButton* cbCutMargin = gbCutMargin->addCheckButton("cut margin", tr("切白边"));
    CoNumberEditor* edMaxMargin = gbCutMargin->addNumberEditor("max margin", tr("不超过:"), tr("%"), 50);
    CoNumberEditor* edIgnoreSize = gbCutMargin->addNumberEditor("ignore size", tr("过滤块大小:"), tr("像素"), 500);
    cbCutMargin->restrictOther(edMaxMargin);
    cbCutMargin->restrictOther(edIgnoreSize);

    // degree align
    CoGroupBox* gbDegreeAlign = m_viewPage->addGroupBox("degree align", tr("倾斜校正"));
    CoCheckButton* cbDegreeAlign = gbDegreeAlign->addCheckButton("degree align", tr("倾斜校正"));
    gbDegreeAlign->addStretch(1);
    gbCutMargin->addStretch(1);
    CoNumberEditor* edMinDegree = gbDegreeAlign->addNumberEditor("min degree", tr("当倾斜角大于:"), tr("度"), 30, 0.1f);
    cbDegreeAlign->restrictOther(edMinDegree);

    m_viewPage->addStretch(1);

    Out_Log(__FUNCTION__, COCLASSNAME);
}

void SettingDlg::initViewPage()
{
    In_Log(__FUNCTION__, COCLASSNAME);

    int option = m_profile->imgProfile.option;

    m_viewPage->getCheckButton("divide", "divide")->setChecked(option & Opt_DividePage);

    if (option & Opt_RightToLeft)
    {
        m_viewPage->getRadioButtonGroup("sequence", "sequence")->select(0);
    }
    else
    {
        m_viewPage->getRadioButtonGroup("sequence", "sequence")->select(1);
    }

    m_viewPage->getCheckButton("cut margin", "cut margin")->setChecked(option & Opt_CutMargin);

    m_viewPage->getNumberEditor("cut margin", "max margin")->setValue(m_profile->imgProfile.maxMarginPercent);

    m_viewPage->getNumberEditor("cut margin", "ignore size")->setValue(m_profile->imgProfile.ignoreSize);

    m_viewPage->getCheckButton("degree align", "degree align")->setChecked(option & Opt_Align);

    m_viewPage->getNumberEditor("degree align", "min degree")->setValue(m_profile->imgProfile.minDegree);

    Out_Log(__FUNCTION__, COCLASSNAME);
}

void SettingDlg::saveViewPage()
{
    In_Log(__FUNCTION__, COCLASSNAME);

    int& option = m_profile->imgProfile.option;

    option &= ~(Opt_DividePage | Opt_RightToLeft | Opt_CutMargin | Opt_Align);

    if (m_viewPage->getCheckButton("divide", "divide")->isChecked())
    {
        option |= Opt_DividePage; 
    }

    if (m_viewPage->getRadioButtonGroup("sequence", "sequence")->selected() == 0)
    {
        option |= Opt_RightToLeft; 
    }

    if (m_viewPage->getCheckButton("cut margin", "cut margin")->isChecked())
    {
        option |= Opt_CutMargin; 
        m_profile->imgProfile.maxMarginPercent = m_viewPage->getNumberEditor("cut margin", "max margin")->getValue();
        m_profile->imgProfile.ignoreSize = m_viewPage->getNumberEditor("cut margin", "ignore size")->getValue();
    }

    if (m_viewPage->getCheckButton("degree align", "degree align")->isChecked())
    {
        option |= Opt_Align; 
        m_profile->imgProfile.minDegree = m_viewPage->getNumberEditor("degree align", "min degree")->getValue();
    }

    Out_Log(__FUNCTION__, COCLASSNAME);
}

bool SettingDlg::popup(){
    In_Log(__FUNCTION__, COCLASSNAME);

    initModePage();
    initViewPage();

    if (m_tabbar.GetSelectedButton() == TAB_KEY)
    {
        m_keyPage->initByKeyMap();
    }
    else
    {
        m_isKeyPageInited = false;
    }

    if (m_tabbar.GetSelectedButton() == TAB_GESTURE)
    {
        m_gesturePage->initByGestureMap();
    }
    else
    {
        m_isGesturePageInited = false;
    }

    if (exec() == Accepted)
    {
        saveModePage();
        saveViewPage();

        if (m_isKeyPageInited)
        {
            m_keyPage->writeToKeyMap();
        }

        if (m_isGesturePageInited)
        {
            m_gesturePage->writeToGestureMap();
        }

        Out_Log(__FUNCTION__, COCLASSNAME);
        return true;
    }

    Out_Log(__FUNCTION__, COCLASSNAME);
    return false;
}

void SettingDlg::clickedOK(){
    In_Log(__FUNCTION__, COCLASSNAME);

    if (!m_gesturePage->isConflict())
    {
        accept();
    }

    Out_Log(__FUNCTION__, COCLASSNAME);
}

void SettingDlg::mouseCtlEvent(GestureEvent* event)
{
    switch (event->gesture)
    {
    case DragUp:
        {
            QScrollBar* bar = m_vcScrArea[m_tabbar.GetSelectedButton()]->verticalScrollBar();
            int step = bar->pageStep();
            int pos = bar->value();
            bar->setValue(pos + step);
        }
        break;
    case DragDown:
        {
            QScrollBar* bar = m_vcScrArea[m_tabbar.GetSelectedButton()]->verticalScrollBar();
            int step = bar->pageStep();
            int pos = bar->value();
            bar->setValue(pos - step);
        }
        break;
    case DragLeft:
        {
            QScrollBar* bar = m_vcScrArea[m_tabbar.GetSelectedButton()]->horizontalScrollBar();
            int step = bar->pageStep();
            int pos = bar->value();
            bar->setValue(pos + step);
        }
        break;
    case DragRight:
        {
            QScrollBar* bar = m_vcScrArea[m_tabbar.GetSelectedButton()]->horizontalScrollBar();
            int step = bar->pageStep();
            int pos = bar->value();
            bar->setValue(pos - step);
        }
        break;

    default:
        break;
    }
}

